﻿using NetworkCommsDotNet;
using NetworkCommsDotNet.Connections;
using NetworkCommsDotNet.Connections.TCP;
using NetworkCommsDotNet.DPSBase;
using System;
using System.Net;
using System.Threading;

namespace NetWorkTcpLibrary
{
    #region 托管TCP客户端

    /// <summary>
    /// 托管Tcp连接
    /// </summary>
    public class NetWorkTcpClient
    {
        #region 所需

        /// <summary>
        /// 连接对象
        /// </summary>
        public Connection connection = null;

        /// <summary>
        /// 重连次数事件
        /// </summary>
        public event Action<ConnectionInfo, int> ReConnectNumEvent;

        /// <summary>
        /// 接收到的消息处理事件
        /// </summary>
        public event Action<Connection, XYZ> EventMessageHandle;

        /// <summary>
        /// 接收到的返回的消息处理事件
        /// </summary>
        public event Action<Connection, string> EventReturnMessageHandle;

        private int reConnectNum = 0;

        /// <summary>
        /// 重连次数
        /// </summary>
        private int ReConnectNum
        {
            get { return reConnectNum; }
            set
            {
                reConnectNum = value;
                ReConnectNumEvent?.Invoke(connnectionInfo, reConnectNum);
            }
        }

        /// <summary>
        /// 连接信息对象
        /// </summary>
        public ConnectionInfo connnectionInfo = null;

        /// <summary>
        /// 初次连接最大的重连次数，为0的是否为无线重连
        /// </summary>
        public int ReconnectionMaxNum = 0;

        /// <summary>
        /// 状态改变触发的事件
        /// </summary>
        public event Action<ConnectionInfo, bool> EventStateChangesEvent;//状态改变触发的事件

        /// <summary>
        /// 连接状态
        /// </summary>
        private bool OnlineStatus = false;

        /// <summary>
        /// 接收到的消息名称
        /// </summary>
        private string ReceviceName = string.Empty;

        /// <summary>
        ///返回的消息的名称
        /// </summary>
        private string ReturnName = string.Empty;

        /// <summary>
        ///自动重连标识（默认启动）
        /// </summary>
        public static bool IsRepetitionStatus = true;

        /// <summary>
        /// 自动重连事件触发标志
        /// </summary>
        private bool ServerNotifyClose = false;

        /// <summary>
        /// 初次连接线程锁辅助对象
        /// </summary>
        private static Object locker = new Object();

        #endregion 所需

        /// <summary>
        /// Tcp连接构造（本地端口号随机）
        /// </summary>
        /// <param name="StrRemotePoint">服务器ip地址和端口</param>
        /// <param name="_RecName">收到的消息名称</param>
        /// <param name="_ReturnName">返回的消息名称</param>
        public NetWorkTcpClient(string StrRemotePoint, string _RecName, string _ReturnName)
        {
            ReceviceName = _RecName;
            ReturnName = _ReturnName;
            string[] thePointArr = StrRemotePoint.Split(':');
            IPEndPoint RemotePoint = new IPEndPoint(IPAddress.Parse(thePointArr[0].ToString()), Convert.ToInt32(thePointArr[1]));//服务器ip地址
            connnectionInfo = new ConnectionInfo(RemotePoint);
            NetworkComms.DisableLogging();//关闭日志
            //IsRepetitionStatus = true;//自动重连标识赋值
            Thread Td = new Thread(new ThreadStart(QDConction));//初次连接的线程
            Td.IsBackground = true;//设置为后台线程
            Td.Start();//启动连接线程
        }

        /// <summary>
        /// Tcp连接构造（指定本地端口号随机）
        /// </summary>
        /// <param name="StrRemotePoint">服务器ip地址和端口</param>
        /// <param name="LocalRemotePoint">本地ip地址和端口</param>
        /// <param name="_RecName">收到的消息名称</param>
        /// <param name="_ReturnName">返回的消息名称</param>
        public NetWorkTcpClient(string StrRemotePoint,string LocalRemotePoint, string _RecName="", string _ReturnName="")
        {
            ReceviceName = _RecName;
            ReturnName = _ReturnName;
            string[] thePointArr = StrRemotePoint.Split(':');
            IPEndPoint RemotePoint = new IPEndPoint(IPAddress.Parse(thePointArr[0].ToString()), Convert.ToInt32(thePointArr[1]));//服务器ip地址
            string[] LocalPointArr = LocalRemotePoint.Split(':');
            IPEndPoint LocalPoint = new IPEndPoint(IPAddress.Parse(LocalPointArr[0].ToString()), Convert.ToInt32(LocalPointArr[1]));//服务器ip地址
            connnectionInfo = new ConnectionInfo(RemotePoint, LocalPoint);
            NetworkComms.DisableLogging();//关闭日志
            IsRepetitionStatus = true;//自动重连标识赋值
            Thread Td = new Thread(new ThreadStart(QDConction));//初次连接的线程
            Td.IsBackground = true;//设置为后台线程
            Td.Start();//启动连接线程
        }

        /// <summary>
        /// 尝试建立连接
        /// </summary>
        /// <returns>是否连接成功</returns>
        private bool TryConnection()
        {
            try
            {
                NetworkComms.ClearDic();
                connection?.CloseConnection(true);//如果连接已经存在需要先关闭再来连接
                //如果不成功，会弹出异常信息
                SendReceiveOptions sro = new SendReceiveOptions(DPSManager.GetDataSerializer<ProtobufSerializer>(), null, null);//指定序列化方式
                NetworkComms.DisableLogging();//关闭日志
                connection = TCPConnection.GetConnection(connnectionInfo, sro);
                NetworkComms.DisableLogging();//关闭日志
                ReConnectNum = 0;
                if (OnlineStatus != true)
                {
                    EventStateChangesEvent?.Invoke(connnectionInfo, true);//连接状态改变触发状态改变事件
                    OnlineStatus = !OnlineStatus;
                }
                return true;
            }
            catch (Exception ex)
            {
                ReConnectNum++;
                Thread.Sleep(2000);
                if (OnlineStatus != false)
                {
                    EventStateChangesEvent?.Invoke(connnectionInfo, false);//连接状态改变触发状态改变事件
                    OnlineStatus = !OnlineStatus;
                }
                return false;
            }
        }

        /// <summary>
        /// 创建连接
        /// </summary>
        private void QDConction()
        {
            lock (locker)
            {
                if (ReconnectionMaxNum == 0)//为0 的时候无限重连
                {
                    while (connection == null)
                    {
                        if (IsRepetitionStatus)//是否阻断重连
                        {
                            if (TryConnection())//尝试连接
                            {
                                break;
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < ReconnectionMaxNum; i++)
                    {
                        if (IsRepetitionStatus)//是否阻断重连
                        {
                            if (TryConnection())//尝试连接
                            {
                                break;
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                }
                if (IsRepetitionStatus)
                {
                    //订阅连接信息类中的连接状态改变事件
                    connnectionInfo.StateChanged += new EventHandler<StringEventArgs>(connnectionInfo_StateChanged);
                    connection.AppendIncomingPacketHandler<XYZ>(ReceviceName, ObjMessgeHandler);//接收到的消息处理
                    connection.AppendIncomingPacketHandler<string>(ReturnName, StringMessgeHandler);//返回的消息处理
                }
            }
        }

        /// <summary>
        /// 返回的消息处理
        /// </summary>
        /// <param name="packetHeader"></param>
        /// <param name="connection"></param>
        /// <param name="incomingObject"></param>
        private void StringMessgeHandler(PacketHeader packetHeader, Connection connection, string incomingObject)
        {
            EventReturnMessageHandle?.Invoke(connection, incomingObject);
        }

        /// <summary>
        /// 接收到的消息处理
        /// </summary>
        /// <param name="packetHeader"></param>
        /// <param name="connection"></param>
        /// <param name="incomingObject"></param>
        private void ObjMessgeHandler(PacketHeader packetHeader, Connection connection, XYZ incomingObject)
        {
            EventMessageHandle?.Invoke(connection, incomingObject);
        }

        /// <summary>
        /// Tcp断线自动重连事件触发的方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void connnectionInfo_StateChanged(object sender, StringEventArgs e)
        {
            if (ServerNotifyClose == false)
            {
                //设置为重连模式
                connnectionInfo.ReconnectFlag = true;
                if (OnlineStatus != false)
                {
                    EventStateChangesEvent?.Invoke(connnectionInfo, false);//连接状态改变触发状态改变事件
                    OnlineStatus = !OnlineStatus;
                }
                do
                {
                    if (IsRepetitionStatus)//是否阻断重连
                    {
                        if (TryConnection())
                        {
                            break;
                        }
                    }
                    else
                    {
                        break;
                    }
                }
                while (true);
            }
        }

        /// <summary>
        /// 带返回的发送消息
        /// </summary>
        /// <typeparam name="X">发送的数据类型</typeparam>
        /// <typeparam name="T">接收的数据类型</typeparam>
        /// <param name="SendName">发送消息名称</param>
        /// <param name="ReceiveName">应答消息名称</param>
        /// <param name="SendReceive">发送的数据</param>
        /// <param name="Seconds">接收数据等待时间(毫秒)</param>
        /// <returns></returns>
        public bool SendReturnObj<X, T>(string SendName, string ReceiveName, X SendReceive, Int32 Seconds)
        {
            if (connection == null)
            {
                return false;
            }
            else
            {
                if (connnectionInfo.ConnectionState == ConnectionState.Established)
                {
                    try
                    {
                        connection.SendReceiveObject<X, T>(SendName, ReceiveName, Seconds, SendReceive);
                    }
                    catch (Exception)
                    {
                        return false;
                    }
                }
                return true;
            }
        }

        /// <summary>
        /// Tcp发送消息
        /// </summary>
        /// <typeparam name="X">发送数据类型</typeparam>
        /// <typeparam name="HandleName">消息名称</typeparam>
        /// <param name="SendReceive">发送的消息</param>
        public virtual bool SendObj<X>(string HandleName, X SendReceive)
        {
            if (connection == null)
            {
                return false;
            }
            else
            {
                if (connnectionInfo.ConnectionState == ConnectionState.Established)
                {
                    try
                    {
                        //SendReceiveOptions sro = new SendReceiveOptions(DPSManager.GetDataSerializer<ProtobufSerializer>(), null, null);//指定序列化方式
                        connection.SendObject(HandleName, SendReceive);
                        //connection.SendObject(HandleName, SendReceive,sro);
                    }
                    catch (Exception e)
                    {
                        return false;
                    }
                }
                return true;
            }
        }

        /// <summary>
        /// 关闭连接
        /// </summary>
        public void StopClient()
        {
            IsRepetitionStatus = false;//阻断所有重连
            if (connection != null)
            {
                connection.CloseConnection(false);
                connection.Dispose();

            }
        }
    }

    #endregion 托管TCP客户端
}